#pragma once

template <typename T>
hIntervalEndpoint<T>::hIntervalEndpoint(hIntervalEndpointBit flag)
{
	do 
	{
		if (flag == hIntervalEndpointBit::None)
			break;

		if (flag & hIntervalEndpointBit::Open)
			_close = 0;

		if (flag & hIntervalEndpointBit::Close)
			_close = 1;

		if (flag & hIntervalEndpointBit::Right)
			_left = 0;

		if (flag & hIntervalEndpointBit::Left)
			_left = 1;
	} while (0);

	if (_left)
		_value = std::numeric_limits<T>::min();
	else
		_value = std::numeric_limits<T>::max();
}

template <typename T>
std::ostream& hIntervalEndpoint<T>::fillOs(std::ostream& os) const
{
	if (_left)
	{
		os << (_close ? "[" : "(");
		if (std::is_signed_v<T> && _value == std::numeric_limits<T>::min())
			os << "-U";
		else
			os << _value;
	}
	else
	{
		if (_value == std::numeric_limits<T>::max())
			os << "+U";
		else
			os << _value;

		os << (_close ? "]" : ")");
	}

	return os;
}

template <typename T>
void hIntervalEndpoint<T>::swap(hIntervalEndpoint& other)
{
	std::swap(_close, other._close);
	std::swap(_value, other._value);
}

template <typename T>
constexpr std::strong_ordering hIntervalEndpoint<T>::operator<=>(const hIntervalEndpoint& other) const
{
	assert(_left ^ ~other._left);

	if (_value != other._value)
		return _value <=> other._value;

	if (_close == other._close)
		return std::strong_ordering::equal;

	if (_left)
	{
		if (_close)
			return std::strong_ordering::less;
		else
			return std::strong_ordering::greater;
	}

	return _close <=> other._close;
}

template <typename T>
hInterval<T>::hInterval(const char* str)
{
	convert(str, 0);
}

template <typename T>
hInterval<T>::hInterval(bool leftClose, T leftVal, bool rightClose, T rightVal)
{
	_left._close = leftClose;
	_left._value = leftVal;
	_right._close = rightClose;
	_right._value = rightVal;
}

template <typename T>
bool hInterval<T>::vaild() const
{
	switch ((_left.val() <=> _right.val())._Value)
	{
	case std::strong_ordering::equal._Value:
		if (_left.close() && _right.close())
			return true;
		else
			return false;
	case std::strong_ordering::less._Value:
		return true;
	case std::strong_ordering::greater._Value:
		return false;
	default:
		break;
	}

	return false;
}

template <typename T>
bool hInterval<T>::overlap(const hInterval& other) const
{
	switch ((_left.val() <=> other._right.val())._Value)
	{
	case std::strong_ordering::equal._Value:
		if (_left.close() && other._right.close())
			return true;
		else
			return false;
	case std::strong_ordering::less._Value:
		break;
	case std::strong_ordering::greater._Value:
	default:
		return false;
	}

	switch ((_right.val() <=> other._left.val())._Value)
	{
	case std::strong_ordering::equal._Value:
		if (_right.close() && other._left.close())
			return true;
		else
			return false;
	case std::strong_ordering::greater._Value:
		break;
	case std::strong_ordering::less._Value:
	default:
		return false;
	}

	return true;
}

template <typename T>
bool hInterval<T>::contain(const hInterval& other) const
{
	switch ((_left <=> other._left)._Value)
	{
	case std::strong_ordering::greater._Value:
		return false;
	case std::strong_ordering::equal._Value:
	case std::strong_ordering::less._Value:
		break;
	default:
		return false;
	}

	switch ((_right <=> other._right)._Value)
	{
	case std::strong_ordering::less._Value:
		return false;
	case std::strong_ordering::equal._Value:
	case std::strong_ordering::greater._Value:
		break;
	default:
		return false;
	}

	return true;
}

template <typename T>
constexpr std::strong_ordering hInterval<T>::operator<=>(const hInterval& other) const
{
	if (_left != other._left)
		return _left <=> other._left;

	return _right <=> other._right;
}

template <typename T>
bool hInterval<T>::convert(const char* str, size_t len)
{
	if (!str)
		return true;

	std::string intvStr = str;
	std::string::size_type frontPos = intvStr.find_first_not_of(' ');
	if (std::string::npos == frontPos)
		return true;

	bool hasLeftIntv = false, hasRightIntv = false;
	switch (intvStr[frontPos])
	{
		case '(':
			_left._close = 0;
		case '[':
			++frontPos;
			hasLeftIntv = true;
			break;
		default:
			break;
	}	
	
	switch (intvStr[intvStr.find_last_not_of(' ')])
	{
		case ')':
			_right._close = 0;
		case ']':
			hasRightIntv = true;
			break;
		default:
			break;
	}

	std::string::size_type begPos = intvStr.find_first_not_of(' ', frontPos);
	std::string::size_type commaPos = intvStr.find(',');
	if (std::string::npos == commaPos)
	{
		T tmpVal = T();
		if (std::from_chars(intvStr.data() + begPos, intvStr.data() + intvStr.size(), tmpVal).ec != std::errc())
			return true;

		if (!hasLeftIntv && !hasRightIntv)
		{
			_left._value = _right._value = tmpVal;
			return true;
		}

		if (hasLeftIntv)
			_left._value = tmpVal;

		if (hasRightIntv)
			_right._value = tmpVal;
	}
	else
	{
		std::from_chars(intvStr.data() + begPos, intvStr.data() + commaPos, _left._value);
		std::string::size_type rightBegPos = intvStr.find_first_not_of(' ', commaPos + 1);
		if (std::string::npos == rightBegPos)
			return true;

		std::from_chars(intvStr.data() + rightBegPos, intvStr.data() + intvStr.size(), _right._value);

		if (_left._value > _right._value)
			std::swap(_left, _right);
	}

	return true;
}

template <typename T>
std::ostream& hInterval<T>::fillOs(std::ostream& os) const
{
	return os << _left << "," << _right;
}
